package com.qdu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Lists;
import com.qdu.commons.RedisKey;
import com.qdu.commons.Result;
import com.qdu.entity.User;
import com.qdu.mapper.UserMapper;
import com.qdu.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qdu.service.RedisStartupService;
import com.qdu.vo.UserPointRankVO;
import com.qdu.vo.WxUserInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.jdbc.Null;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.apache.commons.lang3.time.DateUtils;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author ellery2018
 * @since 2022-03-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    private final UserMapper userMapper;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RedisStartupService redisStartupService;

    @Override
    public void addAnswerNumber(Integer userId) {
        User user=userMapper.selectById(userId);
        user.setAnswerNumber(user.getAnswerNumber()+1);
        userMapper.updateById(user);
    }

    @Override
    public Integer findAnswerNumber(Integer userId) {
        User user=userMapper.selectById(userId);
        return user.getAnswerNumber();
    }

    @Override
    public boolean sameChangeDate(Integer userId) {
        Date mydate = new Date();
        User user=userMapper.selectById(userId);
        Date lastDate=user.getRecentStepExchange();
        //System.out.println(mydate+"!!!!!!!!!!!!!!!!!!!!!!!!!!"+lastDate+"$$$$$$$$$$$"+(DateUtils.isSameDay(mydate,lastDate)));
        if(lastDate==null||DateUtils.isSameDay(mydate,lastDate)==false){
            user.setRecentStepExchange(mydate);
            userMapper.updateById(user);
            return true;
        }
        else{
            return false;
        }
    }

    @Override
    public boolean signGetPower(Integer userId) {
        User user=userMapper.selectById(userId);
        Integer afterPower= user.getHealthPower()+40000;
//        System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!"+afterPower);
        user.setHealthPower(afterPower);
        userMapper.updateById(user);
        return  true;
    }

    @Override
    public boolean sameDate(Integer userId) {
        Date mydate = new Date();
        User user=userMapper.selectById(userId);
        Date lastDate=user.getRecentSignedIn();
//        System.out.println(mydate+"!!!!!!!!!!!!!!!!!!!!!!!!!!"+lastDate+"$$$$$$$$$$$"+(DateUtils.isSameDay(mydate,lastDate)));
        if(lastDate==null||DateUtils.isSameDay(mydate,lastDate)==false){
//            System.out.println(mydate+"!!!!!!!!!!!!!!!!!!!!!!!!!!"+lastDate+"$$$$$$$$$$$"+(DateUtils.isSameDay(mydate,lastDate)));
            user.setRecentSignedIn(mydate);
            userMapper.updateById(user);
            return true;
        }
        else{
           return false;
        }
    }

    public Result unbind(User user){
        user.setOpenId("");
        userMapper.updateById(user);
        return Result.SUCCESS();
    }
    @Override
    public boolean isUnion(String openid) {
        LambdaQueryWrapper<User> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(User::getOpenId,openid);
        return userMapper.selectOne(wrapper)!=null;

    }


    @Override
    public void updateHealthPower(Integer userId, Integer healthPowerFee) {
        User temUser = baseMapper.selectById(userId);
        Integer nowHealthPower = temUser.getHealthPower();
        Integer afterChangeFee = nowHealthPower-healthPowerFee;
        System.out.println(afterChangeFee);
        temUser.setHealthPower(afterChangeFee);
        baseMapper.updateById(temUser);
    }

    @Override
    public Integer findHealthPower(Integer userId) {
        User temUser = baseMapper.selectById(userId);
        return temUser.getHealthPower();
    }

    /**
     *
     * @param user 需要操作的用户
     * @param point 总积分
     * @return
     */
    public Result addPoint (User user, Integer point) {
        if (Objects.isNull(user)) return Result.FAIL("无效的用户");
        user.setPoint(point);
        userMapper.updateById(user);

        //将积分存储到redis
        redisTemplate.opsForZSet().incrementScore(RedisKey.RANK, user.getId(), point);
        return Result.SUCCESS();
    }

    public Result getMyRank(Integer reqId) {
        UserPointRankVO uservo = new UserPointRankVO();
        BeanUtils.copyProperties(redisTemplate.opsForHash().get(RedisKey.ALL_USER_INFO, reqId.toString()),uservo);
        Long myRank = redisTemplate.opsForZSet().reverseRank(
                RedisKey.RANK, reqId
        );
        log.info("获取本人积分{}",uservo);
        Double point = redisTemplate.opsForZSet().score(RedisKey.RANK, reqId);
        uservo.setPoint(point.intValue());
        uservo.setRank(myRank.intValue()+1);
        return Result.SUCCESS(uservo);

    }

    public Result getTotalRank() {
        if (!redisTemplate.hasKey(RedisKey.RANK)) redisStartupService.initRouteTrace();
        Set<ZSetOperations.TypedTuple<Integer>> rangeWithScores =
                redisTemplate.opsForZSet().reverseRangeWithScores(
                        RedisKey.RANK,0,19
                );
        if (rangeWithScores == null || rangeWithScores.isEmpty()) {
            return Result.FAIL("网络错误");
        }

        // 用户id
        List<Integer> rankUserIds = Lists.newArrayList();
        // 构建 <用户姓名，积分> map 需要维护
        Map<Integer, UserPointRankVO> ranksMap = new LinkedHashMap<>();
        //初始化rank 排名
        int rank =1;
        for (ZSetOperations.TypedTuple<Integer > rangeWithScore : rangeWithScores) {
            //用户id
            Integer userId = rangeWithScore.getValue();
            //积分
            int points = Objects.requireNonNull(rangeWithScore.getScore()).intValue();
            // 将userId D集合
            rankUserIds.add(userId);
            UserPointRankVO userPointRankVO =new UserPointRankVO();
            userPointRankVO.setId(userId);
            userPointRankVO.setRank(rank);
            userPointRankVO.setPoint(points);
            // 将vo对象添加到Map
            ranksMap.put(userId, userPointRankVO);
            // 排名++
            rank++;
        }
        if (!redisTemplate.hasKey(RedisKey.RANK)) redisStartupService.initAllUserInfo();
        Map<Integer,User> userInfoMaps = redisTemplate.opsForHash().entries(RedisKey.ALL_USER_INFO);
        //填充 姓名和头像
        userInfoMaps.entrySet().parallelStream().forEach(userInfoMap->processUserInfo(userInfoMap ,ranksMap));

//        // 判断请求人是否在ranks中，如果在，添加标记直接返回
//        if (ranksMap.containsKey(reqId)) {
//            UserPointRankVO rankVO = ranksMap.get(reqId);
//            rankVO.setMe(true);
//            return Result.SUCCESS(Lists.newArrayList(ranksMap.values()));
//        }
//
//        // 如果不再ranks中，获取个人排名追加到最后
//        // 获取排名
//        Long myRank = redisTemplate.opsForZSet().reverseRank(
//                RedisKey.RANK, reqId
//        );
//        if (myRank!=null){
//            UserPointRankVO me=new UserPointRankVO();
//            BeanUtils.copyProperties(myInfo, me);
//            //排名从0开始
//            me.setRank(myRank.intValue()+1);
//            me.setMe(true);
//            //获取积分
//            Double points = redisTemplate.opsForZSet().score(RedisKey.RANK, reqId);
//            assert points!=null;
//            me.setPoint(points.intValue());
//            ranksMap.put(reqId, me);
//        }
        log.info("获取积分榜单");
        return Result.SUCCESS(Lists.newArrayList(ranksMap.values()));
    }

    private void processUserInfo (Map.Entry<Integer, User> userInfoMap, Map<Integer, UserPointRankVO> ranksMap) {
            User user =userInfoMap.getValue();
            if (!ranksMap.containsKey(user.getId())) return;
            UserPointRankVO rankVO = ranksMap.get(user.getId());
            rankVO.setName(user.getName());
            rankVO.setAvatarUrl(user.getAvatarUrl());
    }


    @Override
    public boolean completeGetPoint(Integer userId) {
        User user=userMapper.selectById(userId);
        Integer afterPoint= user.getPoint()+100 ;
        addPoint(user,afterPoint);
        return  true;
    }


}